﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using VNet.VisiSuite.Common;
using VNet.VisiSuite.Common.Resource;
using VNet.VisiSuite.Controls;
using VNet.VisiSuite.Service.Contact.Message.Base;
using VNet.VisiSuite.Service.Contact.Message.Item;
using VNet.VisiSuite.VisiAdmin.Common.Helpers;
using VNet.VisiSuite.VisiAdmin.Models;
using VNet.VisiSuite.VisiAdmin.Providers;
using VNet.VisiSuite.VisiAdmin.Views;
using VNet.VisiSuite.Common.Helper;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Json;

namespace VNet.VisiSuite.VisiAdmin.ViewModels
{
    public class StatusViewModel : BaseViewModel
    {
        #region Fields

        private string _contentPaneHeader;
        private VNetMenuItem _addNewIcon;
        private AreaModel _currentAreaModel;
        private ObservableCollection<VisiBoardStatusModel> _visiBoardStatuses;
        private VisiBoardStatusModel _selectedObject;
        private VisiBoardStatusModel _pendingObject;
        private VisiBoardStatusModel _cloneSelectedVisiBoardStatus;

        #endregion

        #region Properties

        public string ContentPaneHeader
        {
            get { return _contentPaneHeader; }
            set
            {
                if (_contentPaneHeader == value) return;
                _contentPaneHeader = value;
                OnPropertyChanged("ContentPaneHeader");
            }
        }

        public ObservableCollection<VisiBoardStatusModel> VisiBoardStatuses
        {
            get
            {
                return _visiBoardStatuses;
            }
            set
            {
                _visiBoardStatuses = value;
                OnPropertyChanged("VisiBoardStatuses");
            }
        }

        public VisiBoardStatusModel CloneSelectedVisiBoardStatus
        {
            get
            {
                return _cloneSelectedVisiBoardStatus;
            }
            set
            {
                _cloneSelectedVisiBoardStatus = value;
                OnPropertyChanged("CloneSelectedVisiBoardStatus");
            }
        }

        public VisiBoardStatusModel SelectedObject
        {
            get
            {
                return _selectedObject;
            }
            set
            {
                if (_selectedObject != null)
                {
                    if (IsPendingChange(null))
                    {
                        return;
                    }
                }

                _selectedObject = null;
                OnPropertyChanged("SelectedObject");

                _selectedObject = value;
                if (value != null)
                {
                    CloneAndBindingVisiBoardStatus(_selectedObject);
                }
                OnPropertyChanged("SelectedObject");
            }
        }

        public RelayCommand SaveVisiBoardStatusCommand { get; set; }
        public RelayCommand CancelVisiBoardStatusCommand { get; set; }
        public RelayCommand DeleteVisiBoardStatusCommand { get; set; }

        #endregion

        #region Constructors

        public StatusViewModel()
        {
            TopLeftButtonIcons = new ObservableCollection<VNetMenuItem> { new VNetMenuItem(null, "Return to previous screen", CommonConstants.VNetIcon.AppbarArrowLeft, VNetMenuItemType.WhiteBackgroundTheme, OnExit), };
            _addNewIcon = new VNetMenuItem(null, "Refresh Statuses", CommonConstants.VNetIcon.AppbarRefresh, VNetMenuItemType.WhiteBackgroundTheme, RefreshData);
            TopRightButtonIcons = new ObservableCollection<VNetMenuItem> { _addNewIcon };

            SaveVisiBoardStatusCommand = new RelayCommand(DoSaveVisiBoardStatus);
            CancelVisiBoardStatusCommand = new RelayCommand(DoCancelVisiBoardStatus);
            DeleteVisiBoardStatusCommand = new RelayCommand(DoDeleteVisiBoardStatus);
        }

        #endregion

        #region Callbacks

        private void OnAddNewVisiBoardStatus()
        {
            CloneSelectedVisiBoardStatus = new VisiBoardStatusModel { IsAddNew = true, Enabled = true, IsCancelEnable = true};
        }

        private void DoSaveVisiBoardStatus(object obj)
        {
            ErrorMessage = null;
            if (!CloneSelectedVisiBoardStatus.IsValid())
            {
                IsClosing = false;
                _pendingObject = null;
                return;
            }

            var item = new CellItem
            {
                CellId = CloneSelectedVisiBoardStatus.CellId,
                AreaId = CloneSelectedVisiBoardStatus.AreaId,
                CellName = CloneSelectedVisiBoardStatus.CellName.TrimSafety(),
                Description = CloneSelectedVisiBoardStatus.Description.TrimSafety(),
                Password = CloneSelectedVisiBoardStatus.Password.TrimSafety(),
                Enabled = CloneSelectedVisiBoardStatus.Enabled,
                VisiCentralGroup = (byte)CloneSelectedVisiBoardStatus.VisiCentralGroup,
                VisiCentralRow = CloneSelectedVisiBoardStatus.VisiCentralRow,
                VisiCentralColumn = CloneSelectedVisiBoardStatus.VisiCentralColumn
            };

            ErrorMessage = null;
            IsBusy = true;
            if (CloneSelectedVisiBoardStatus.IsAddNew)
                DoAsync(CellProvider.InsertCell, InsertVisiBoardStatusCompleted, item);
            else
                DoAsync(CellProvider.UpdateCell, UpdateVisiBoardStatusCompleted, item);

        }

        private void DoCancelVisiBoardStatus(object obj)
        {
            ErrorMessage = null;
            CloneAndBindingVisiBoardStatus(_selectedObject);
        }

        private void DoDeleteVisiBoardStatus(object obj)
        {
            ErrorMessage = null;
            if (MessageBox.Show(string.Format(FormatString.DeleteItemFormat, "VisiBoard Status"), TitleString.ConfirmDeleteTitle, MessageBoxButton.YesNo) == MessageBoxResult.No)
                return;

            IsBusy = true;
            DoAsync(CellProvider.DeleteCell, DeleteVisiBoardStatusCompleted, CloneSelectedVisiBoardStatus.CellId);
        }

        private void GetVisiBoardStatusesCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as GetDataResponse<IList<CellItem>>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    ErrorMessage = response.Error.Description;
                return;
            }

            response.Data = response.Data.OrderBy(t => t.CellName).ToList();
            var list = new ObservableCollection<VisiBoardStatusModel>();
            foreach (var item in response.Data)
            {
                list.Add(new VisiBoardStatusModel
                {
                    CellId = item.CellId,
                    AreaId = item.AreaId,
                    CellName = item.CellName.TrimSafety(),
                    Description = item.Description.TrimSafety(),
                    Password = item.Password.TrimSafety(),
                    Enabled = item.Enabled,
                    VisiCentralGroup = (VisiBoardStatusModel.VisiCentralGroupEnum)item.VisiCentralGroup,
                    VisiCentralRow = item.VisiCentralRow,
                    VisiCentralColumn = item.VisiCentralColumn,

                    CreatedBy = item.CreatedBy,
                    CreatedDate = item.CreatedDate.ToString(FormatString.DateTimeFormat),
                    LastUpdatedBy = item.LastUpdatedBy,
                    LastUpdatedDate = item.LastUpdatedDate.ToString(FormatString.DateTimeFormat),
                });
            }

            VisiBoardStatuses = list;
        }

        private void InsertVisiBoardStatusCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as SaveDataResponse<CellItem>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    CloneSelectedVisiBoardStatus.ErrorMessage = response.Error.Description;

                CloneSelectedVisiBoardStatus.IsCancelEnable = false;
                _pendingObject = null;
                IsClosing = false;
                return;
            }

            if (IsClosing)
            {
                NavigateBack();
                return;
            }

            var newVisiBoardStatus = new VisiBoardStatusModel();
            newVisiBoardStatus.CellId = response.Data.CellId;
            newVisiBoardStatus.AreaId = response.Data.AreaId;
            newVisiBoardStatus.CellName = response.Data.CellName;
            newVisiBoardStatus.Description = response.Data.Description;
            newVisiBoardStatus.Password = response.Data.Password;
            newVisiBoardStatus.Enabled = response.Data.Enabled;
            newVisiBoardStatus.VisiCentralGroup = (VisiBoardStatusModel.VisiCentralGroupEnum)response.Data.VisiCentralGroup;
            newVisiBoardStatus.VisiCentralRow = response.Data.VisiCentralRow;
            newVisiBoardStatus.VisiCentralColumn = response.Data.VisiCentralColumn;
            newVisiBoardStatus.LastUpdatedDate = response.Data.LastUpdatedDate.ToString(FormatString.DateTimeFormat);
            newVisiBoardStatus.LastUpdatedBy = response.Data.LastUpdatedBy;
            newVisiBoardStatus.LastUpdatedDate = response.Data.LastUpdatedDate.ToString(FormatString.DateTimeFormat);
            newVisiBoardStatus.LastUpdatedBy = response.Data.LastUpdatedBy;
            newVisiBoardStatus.CreatedDate = response.Data.CreatedDate.ToString(FormatString.DateTimeFormat);
            newVisiBoardStatus.CreatedBy = response.Data.CreatedBy;

            VisiBoardStatuses.Add(newVisiBoardStatus);

            _selectedObject = null;
            SelectedObject = newVisiBoardStatus;

            SetPendingObject();
        }

        private void UpdateVisiBoardStatusCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as SaveDataResponse<CellItem>;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                if (response != null)
                    CloneSelectedVisiBoardStatus.ErrorMessage = response.Error.Description;

                CloneSelectedVisiBoardStatus.IsCancelEnable = false;
                _pendingObject = null;
                IsClosing = false;
                return;
            }

            if (IsClosing)
            {
                NavigateBack();
                return;
            }

            var selectedVisiBoardStatus = (VisiBoardStatusModel)_selectedObject;

            selectedVisiBoardStatus.CellName = response.Data.CellName;
            selectedVisiBoardStatus.Description = response.Data.Description;
            selectedVisiBoardStatus.Password = response.Data.Password;
            selectedVisiBoardStatus.Enabled = response.Data.Enabled;
            selectedVisiBoardStatus.VisiCentralGroup = (VisiBoardStatusModel.VisiCentralGroupEnum)response.Data.VisiCentralGroup;
            selectedVisiBoardStatus.VisiCentralRow = response.Data.VisiCentralRow;
            selectedVisiBoardStatus.VisiCentralColumn = response.Data.VisiCentralColumn;
            selectedVisiBoardStatus.LastUpdatedDate = response.Data.LastUpdatedDate.ToString(FormatString.DateTimeFormat);
            selectedVisiBoardStatus.LastUpdatedBy = response.Data.LastUpdatedBy;

            selectedVisiBoardStatus.IsChange = false;
            selectedVisiBoardStatus.ErrorMessage = null;
            selectedVisiBoardStatus.IsCancelEnable = false;

            CloneAndBindingVisiBoardStatus(selectedVisiBoardStatus);

            SetPendingObject();
        }

        private void DeleteVisiBoardStatusCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as DeleteDataResponse;
            IsBusy = false;

            if (response == null || !response.Success)
            {
                CloneSelectedVisiBoardStatus.ErrorMessage = response.Error.Description;
                _pendingObject = null;
                IsClosing = false;
                return;
            }

            if (IsClosing)
            {
                NavigateBack();
                return;
            }

            CloneSelectedVisiBoardStatus = null;
            SelectedObject = null;

            var item = VisiBoardStatuses.FirstOrDefault(t => t.CellId == response.DataId);
            if (item != null)
                VisiBoardStatuses.Remove(item);
        }

        #endregion

        #region Helper Methods

        private void SetPendingObject()
        {
            if (_pendingObject != null)
            {
                _cloneSelectedVisiBoardStatus = null;
                SelectedObject = _pendingObject;
                _pendingObject = null;
            }
        }

        private void CloneAndBindingVisiBoardStatus(VisiBoardStatusModel visiBoardStatusModel)
        {
            CloneSelectedVisiBoardStatus = SmartReflection.CloneModel(visiBoardStatusModel);
            CloneSelectedVisiBoardStatus.ShouldValidate = true;
        }

        public bool IsPendingChange(VisiBoardStatusModel value)
        {
            if (_cloneSelectedVisiBoardStatus != null && _cloneSelectedVisiBoardStatus.HasChange())
            {
                switch (ConfirmDialog.Show())
                {
                    case SaveChangesDialogResult.Discard:
                        return false;
                    case SaveChangesDialogResult.Save:
                        _pendingObject = value;
                        DoSaveVisiBoardStatus(null);
                        return true;
                    case SaveChangesDialogResult.Resume:
                        IsClosing = false;
                        _pendingObject = null;
                        return true;
                }
            }
            return false;
        }

        #endregion

        #region Navigation Framework

        public override void OnNavigate(object obj)
        {
            _currentAreaModel = (AreaModel)obj;
            PageTitle = string.Format(TitleString.VisiBoardStatusAdminTitle, _currentAreaModel.AreaName);
            ContentPaneHeader = "VisiBoard Status Properties";
            ErrorMessage = null;
            IsBusy = true;
            DoAsync(CellProvider.GetCells, GetVisiBoardStatusesCompleted, _currentAreaModel.AreaId);
        }

        public override void OnLeave()
        {
            
        }

        private void OnExit()
        {
            if (_selectedObject != null)
            {
                IsClosing = true;
                if (IsPendingChange(null))
                {
                    return;
                }
            }

            NavigateBack();
        }

        private void NavigateBack()
        {
            NavigationManager.NavigateTo(new PlantView(), null);
        }

        #endregion

        #region Polling Calls

        private static string BuildPollingUrl(VisiBoardStatusModel visiBoardStatusModel, bool isVisiBox)
        {
            if (isVisiBox)
            {
                return string.Format("http://VBOX{0}.local:8080/api/status", visiBoardStatusModel.CellName);
            }
            else
            {
                return string.Format("http://VisiBoard{0}.local:8081/api/status", visiBoardStatusModel.CellName);
            }
        }

        private void RefreshData()
        {
            foreach (var model in VisiBoardStatuses)
            {
                

                var vBoardServiceUrl = BuildPollingUrl(model, false);
                var vBoxServiceUrl = BuildPollingUrl(model, true);

#if DEBUGx
                // Use a local test site to return random json for debugging, 
                // in the format: {"Cell":null,"Status":"Offline","Version":"2.0.1","IpAddress":"192.168.1.100","WiFi":"Yes","LastReboot":null}
                vBoardServiceUrl = "http://localhost:8081/api/status";
                vBoxServiceUrl = "http://localhost:8081/api/status";
#endif
                var vboxRequest = new StatusRequestWrapper { CellId = model.CellId, IsVisiBoxStatus = true, RequestUrl = vBoxServiceUrl };
                DoAsync(RetrieveStatus, RetrieveStatusCompleted, vboxRequest);

                var vboardRequest = new StatusRequestWrapper { CellId = model.CellId, IsVisiBoxStatus = false, RequestUrl = vBoardServiceUrl };
                DoAsync(RetrieveStatus, RetrieveStatusCompleted, vboardRequest);

            }
        }

        public static void RetrieveStatus(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            e.Result = null;
            if (worker != null && worker.CancellationPending == false)
            {
                if (worker != null && worker.CancellationPending == false)
                {
                    var model = e.Argument as StatusRequestWrapper;

                    var response = new StatusResponseWrapper() { CellId = model.CellId, IsVisiBoxStatus = model.IsVisiBoxStatus, Success = true };

                    try
                    {
                        // Synchronous Consumption
                        var syncClient = new WebClient();
                        var content = syncClient.DownloadString(model.RequestUrl);

                        // Create the Json serializer and parse the response
                        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(StatusObject));
                        using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(content)))
                        {
                            var statusObject = (StatusObject)serializer.ReadObject(ms);
                            if (statusObject != null)
                            {
                                response.ResultObject = statusObject;
                            }
                        }
                    }
                    catch(Exception ex)
                    {
                        response.Success = false;
                        if (model.IsVisiBoxStatus)
                            response.ErrorMessage = string.Format("Could not retrieve VisiBox status for cell: {0}", model.CellId);
                        else
                            response.ErrorMessage = string.Format("Could not retrieve VisiBoard status for cell: {0}", model.CellId);
                    }
                    
                    e.Result = response;
                }
            }
        }

        private void RetrieveStatusCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var response = e.Result as StatusResponseWrapper;
            IsBusy = false;

            if (response == null || !response.Success || response.ResultObject == null)
            {
                return;
            }

            var model = VisiBoardStatuses.FirstOrDefault(t => t.CellId == response.CellId);
            if (model != null)
            {
                if (response.ResultObject != null && !response.IsVisiBoxStatus)
                {
                    SetVisiBoardResponse(model, response.ResultObject);

                    if (_cloneSelectedVisiBoardStatus != null && _cloneSelectedVisiBoardStatus.CellId == response.CellId)
                    {
                        SetVisiBoardResponse(_cloneSelectedVisiBoardStatus, response.ResultObject);
                    }
                }

                if (response.ResultObject != null && response.IsVisiBoxStatus)
                {
                    SetVisiBoxResponse(model, response.ResultObject);

                    if (_cloneSelectedVisiBoardStatus != null && _cloneSelectedVisiBoardStatus.CellId == response.CellId)
                    {
                        SetVisiBoxResponse(_cloneSelectedVisiBoardStatus, response.ResultObject);
                    }
                }
                OnPropertyChanged("VisiBoardStatuses");
            }
        }

        private void SetVisiBoardResponse(VisiBoardStatusModel model, StatusObject statusObject)
        {
            model.Status = statusObject.Status;
            model.Version = statusObject.Version;
            model.IpAddress = statusObject.IpAddress;
            model.WiFi = statusObject.WiFi;
            model.LastReboot = statusObject.LastReboot;
            model.Battery = statusObject.Battery;
            model.BatteryLife = statusObject.BatteryLife;
            model.BatteryCharging = statusObject.BatteryCharging;
            if (model.OriginalObject != null)
            {
                model.OriginalObject.Status = statusObject.Status;
                model.OriginalObject.Version = statusObject.Version;
                model.OriginalObject.IpAddress = statusObject.IpAddress;
                model.OriginalObject.WiFi = statusObject.WiFi;
                model.OriginalObject.LastReboot = statusObject.LastReboot;
                model.OriginalObject.Battery = statusObject.Battery;
                model.OriginalObject.BatteryLife = statusObject.BatteryLife;
                model.OriginalObject.BatteryCharging = statusObject.BatteryCharging;
            }
        }

        private void SetVisiBoxResponse(VisiBoardStatusModel model, StatusObject statusObject)
        {
            model.VisiBoxStatus = statusObject.Status;
            model.VisiBoxVersion = statusObject.Version;
            model.VisiBoxIpAddress = statusObject.IpAddress;
            model.VisiBoxWiFi = statusObject.WiFi;
            model.VisiBoxLastReboot = statusObject.LastReboot;
            if (model.OriginalObject != null)
            {
                model.OriginalObject.VisiBoxStatus = statusObject.Status;
                model.OriginalObject.VisiBoxVersion = statusObject.Version;
                model.OriginalObject.VisiBoxIpAddress = statusObject.IpAddress;
                model.OriginalObject.VisiBoxWiFi = statusObject.WiFi;
                model.OriginalObject.VisiBoxLastReboot = statusObject.LastReboot;
            }
        }

        #endregion
    }
}
